﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.IO;
using System.IO.IsolatedStorage;
using System.Collections.Generic;
using Microsoft.LightSwitch;
using Microsoft.LightSwitch.Framework;
using Microsoft.LightSwitch.Framework.Client;
using Microsoft.LightSwitch.Presentation;
using Microsoft.LightSwitch.Presentation.Extensions;
using System.Text.RegularExpressions;

namespace LightSwitchApplication
{
    public partial class LocEntryScreen
    {
        static Regex ParseExpr = new Regex(@"(?<Fish>[\p{L}\s-]+) (?<Weight>\p{N}+(?:,\p{N}+)?) (?<Measure>(?:кг)|(?:грамм)). Поймана на (?<Region>[\p{L}\s-]+): (?<Location>[\p{L}\s-\.]+), (?<Bait>[\w\s-]+).", RegexOptions.IgnoreCase);

        partial void ParseReport_Execute()
        {
            var rec = RawReports.SelectedItem;
            if (rec != null)
            {
                var text = rec.Report;
                using (var rd = new StringReader(text))
                {
                    string line;
                    do
                    {
                        line = rd.ReadLine();
                        if (line != null)
                        {
                            try
                            {
                                var match = ParseExpr.Match(line);
                                if (match.Success)
                                {
                                    var res = DataWorkspace.ApplicationData.ParsedReports.AddNew();
                                    res.Bait = match.Groups["Bait"].Captures[0].Value.Trim();
                                    res.Fish = match.Groups["Fish"].Captures[0].Value.Trim();
                                    res.Location = match.Groups["Location"].Captures[0].Value.Trim();
                                    res.Region = match.Groups["Region"].Captures[0].Value.Trim();
                                }
                            }
                            catch
                            {
                                // ignore invalid line
                            }
                        }
                    } while (line != null);
                }
                rec.Delete();
            }
        }

        partial void ParseReport_CanExecute(ref bool result)
        {
            result = RawReports.SelectedItem != null;
        }

        partial void SaveParsedRecords_CanExecute(ref bool result)
        {
            result = ParsedReports.Count > 0;
        }

        partial void SaveParsedRecords_Execute()
        {
            var toSave = ParsedReports.ToArray();
            var fbs = new HashSet<Tuple<int, int>>();
            var fls = new HashSet<Tuple<int, int>>();
            foreach (var item in toSave)
            {
                try
                {
                    var fish = GetEntityByName<Fish, FishAlias>(
                            DataWorkspace.ApplicationData.Fishes,
                            r => r.Name == item.Fish,
                            DataWorkspace.ApplicationData.FishAliases,
                            r => r.Name == item.Fish,
                            a => a.Fish
                        );
                    if (fish == null) continue;
                    var bait = GetEntityByName<Bait, BaitAlias>(
                            DataWorkspace.ApplicationData.Baits,
                            r => r.Name == item.Bait,
                            DataWorkspace.ApplicationData.BaitAliases,
                            r => r.Name == item.Bait,
                            a => a.Bait
                        );
                    if (bait == null) continue;
                    var region = GetEntityByName<Region, RegionAlias>(
                            DataWorkspace.ApplicationData.Regions,
                            r => r.Name == item.Region,
                            DataWorkspace.ApplicationData.RegionAliases,
                            r => r.Name == item.Region,
                            a => a.Region
                        );
                    if (region == null) continue;
                    var location = GetEntityByName<Location, LocationAlias>(
                            DataWorkspace.ApplicationData.Locations,
                            r => r.Name == item.Location && r.Region.Id == region.Id,
                            DataWorkspace.ApplicationData.LocationAliases,
                            r => r.Name == item.Location && r.Location.Region.Id == region.Id,
                            a => a.Location
                        );
                    if (location == null) continue;
                    var fl = DataWorkspace.ApplicationData.FishLocations.Where(r => r.Fish.Id == fish.Id && r.Location.Id == location.Id).FirstOrDefault();
                    if (fl == null)
                    {
                        var key = new Tuple<int, int>(fish.Id, location.Id);
                        if (!fls.Contains(key))
                        {
                            fl = DataWorkspace.ApplicationData.FishLocations.AddNew();
                            fl.Fish = fish;
                            fl.Location = location;
                            fls.Add(key);
                        }
                    }
                    var fb = DataWorkspace.ApplicationData.FishBaits.Where(r => r.Fish.Id == fish.Id && r.Bait.Id == bait.Id).FirstOrDefault();
                    if (fb == null)
                    {
                        var key = new Tuple<int, int>(fish.Id, bait.Id);
                        if (!fbs.Contains(key))
                        {
                            fb = DataWorkspace.ApplicationData.FishBaits.AddNew();
                            fb.Fish = fish;
                            fb.Bait = bait;
                            fbs.Add(key);
                        }
                    }
                    item.Delete();
                }
                catch
                {                    
                    // ignore invalid entry
                }
            }
        }

        private TItem GetEntityByName<TItem, TAlias>(EntitySet<TItem> query, Expression<Func<TItem, bool>> whereFunc, EntitySet<TAlias> aliasQuery, Expression<Func<TAlias, bool>> aliasWhereFunc, Func<TAlias, TItem> aliasItemFunc)
            where TItem : class, IEntityObject
            where TAlias : class, IEntityObject
        {
            var item = query.Where(whereFunc).FirstOrDefault();
            if (item != null)
            {
                return item;
            }
            var alias = aliasQuery.Where(aliasWhereFunc).FirstOrDefault();
            if (alias != null)
            {
                return aliasItemFunc(alias);
            }
            return null;
        }
    }
}
